package com.yk.system.controller;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.yk.api.dataGatherer.dto.TableDTO;
import com.yk.api.dataGatherer.model.RemoteTdEngineService;
import com.yk.api.system.dto.DeviceCopyDTO;
import com.yk.api.system.dto.DeviceDTO;
import com.yk.api.system.dto.GroupDTO;
import com.yk.common.core.constant.NumberConstant;
import com.yk.common.core.constant.TdEngIneConstants;
import com.yk.common.core.domain.BasePageQuery;
import com.yk.common.core.domain.LoginUser;
import com.yk.common.core.domain.PageResult;
import com.yk.common.core.domain.Result;
import com.yk.common.core.enums.DeviceControlsTypeEnum;
import com.yk.common.core.enums.RoleTypeEnum;
import com.yk.common.core.exception.ServiceException;
import com.yk.common.core.utils.LoginHelper;
import com.yk.common.excel.utils.ExcelUtil;
import com.yk.common.log.annotation.Log;
import com.yk.common.log.constant.LogConstants;
import com.yk.common.log.enums.BusinessType;
import com.yk.system.convert.DeviceConvert;
import com.yk.system.convert.GroupConvert;
import com.yk.system.dto.ControlDTO;
import com.yk.system.entity.*;
import com.yk.system.service.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;


/**
 * 设备管理 yk-system
 *
 * @author lmx
 * @date 2023/10/16 18:15
 */
@Api(tags = "设备管理")
@RestController
@RequiredArgsConstructor
@RequestMapping("/device")
public class DeviceController {

    private final DeviceService deviceService;
    private final VariableService variableService;
    private final DeviceUserDetailsService deviceUserDetailsService;
    private final DeviceConvert deviceConvert;
    private final GroupDeviceService groupDeviceService;
    private final GroupService groupService;
    private final GatewayService gatewayService;
    private final UserService userService;
    private final DeviceRoleService deviceRoleService;
    private final RemoteTdEngineService remoteTdEngineService;
    private final TemplateService templateService;
    private final GroupConvert groupConvert;

    @GetMapping("/selectByOnlineDeviceId")
    @ApiOperation("查询所有在线的设备IDs")
    public Result<List<Long>> selectByOnlineDeviceId() {
        LambdaQueryWrapper<Device> lambda = new LambdaQueryWrapper<>();
        lambda.select(Device::getId);
        lambda.eq(Device::getStatus, Boolean.TRUE);
        List<Device> list = Optional.ofNullable(deviceService.list(lambda)).orElse(CollUtil.newArrayList());
        List<Long> ids = list.stream().map(Device::getId).collect(Collectors.toList());
        return Result.data(ids);
    }

    @GetMapping("/userDevice")
    @ApiOperation("获取当前用户创建的设备")
    public Result<List<DeviceDTO>> userDevice() {
        Long userId = LoginHelper.getLoginUserId();
        LambdaQueryWrapper<Device> lambda = new LambdaQueryWrapper<>();
        lambda.select(Device::getId, Device::getDeviceName, Device::getSlaveAddress, Device::getGatewayId, Device::getTemplateId);
        lambda.eq(Device::getCreatedBy, userId);
        List<Device> list = Optional.ofNullable(deviceService.list(lambda)).orElse(CollUtil.newArrayList());
        List<DeviceDTO> returnList = list.stream().map(deviceConvert::entity2Dto).collect(Collectors.toList());
        return Result.data(returnList);
    }

    /**
     * 新增
     */
    @Log(title = "设备", businessType = BusinessType.INSERT)
    @ApiOperation("新增")
    @PostMapping("/add")
    public Result<Void> add(@Validated @RequestBody DeviceDTO dto) {
        long deviceId = IdWorker.getId();
        Device device = deviceConvert.dto2Entity(dto);
        device.setId(deviceId);
        deviceService.add(device, dto.getGroupIds());
        if (StrUtil.isNotEmpty(dto.getNotes())){
            DeviceUserDetails details = new DeviceUserDetails();
            details.setDeviceId(deviceId);
            details.setRemarks(dto.getNotes());
            details.setUserId(LoginHelper.getLoginUserId());
            deviceUserDetailsService.save(details);
        }
        return Result.ok2Log(LogConstants.ADD + dto.getDeviceName());
    }

    /**
     * 设备克隆
     */
    @PostMapping("/copy}")
    @ApiOperation("设备克隆")
    public Result<Void> copy(@RequestBody @Validated DeviceCopyDTO dto) {
        if (Objects.isNull(dto.getDeviceId())) {
            return Result.fail("请选择设备");
        }
        Device device = deviceService.getById(dto.getDeviceId());
        if (Objects.isNull(device)) {
            return Result.fail("设备不存在");
        }

        for (int i = 0; i < dto.getNumber(); i++) {
            device.setId(null);
            device.setStatus(false);
            device.setCreatedBy(null);
            device.setCreatedAt(null);
            device.setUpdatedBy(null);
            device.setUpdatedAt(null);
            device.setDeviceName(device.getDeviceName() + "_副本" + i + 1);
            deviceService.add(device, null);
        }
        return Result.ok2Log(LogConstants.COPY + device.getDeviceName() + "_" + dto.getNumber() + "次");
    }

    /**
     * 编辑
     */
    @Log(title = "设备", businessType = BusinessType.UPDATE)
    @ApiOperation("编辑")
    @PostMapping("/edit")
    public Result<Void> edit(@Validated @RequestBody DeviceDTO dto) {
        Long userId = LoginHelper.getLoginUserId();
        Device device = deviceService.getById(dto.getId());
        Assert.notNull(device, "设备数据异常");
        DeviceRole deviceRole = deviceRoleService.getDeviceRole(dto.getId());
        Assert.notNull(deviceRole, "设备权限异常");
        Long oldTemplateId = device.getTemplateId();
        if (RoleTypeEnum.MANAGE.getCode().equals(deviceRole.getRoleType()) || RoleTypeEnum.ADMIN.getCode().equals(deviceRole.getRoleType())) {
            Device newD = deviceConvert.dto2Entity(dto);
            newD.setNotes(null);
            deviceService.updateById(newD);
            // 变量模板发生变化，删除子表
            if (Objects.nonNull(dto.getTemplateId()) && !oldTemplateId.equals(dto.getTemplateId())) {
                TableDTO tableDTO = new TableDTO();
                tableDTO.setTableName(TdEngIneConstants.TABLE_PREFIX + dto.getId());
                remoteTdEngineService.delTable(tableDTO);
            }
        }
        // 关联场景
        groupDeviceService.relevancyDevice(dto.getId(), userId, dto.getGroupIds());
        DeviceUserDetails details = deviceUserDetailsService.getOne(new LambdaQueryWrapper<DeviceUserDetails>()
                .eq(DeviceUserDetails::getDeviceId, dto.getId())
                .eq(DeviceUserDetails::getUserId, userId));
        if (StrUtil.isNotEmpty(dto.getNotes())){
            if (Objects.isNull(details)){
                details = new DeviceUserDetails();
                details.setDeviceId(dto.getId());
                details.setRemarks(dto.getNotes());
                details.setUserId(LoginHelper.getLoginUserId());
                deviceUserDetailsService.save(details);
            }else {
                if (!details.getRemarks().equals(dto.getNotes())){
                    details.setRemarks(dto.getNotes());
                    deviceUserDetailsService.updateById(details);
                }
            }
        }
        return Result.ok2Log(LogConstants.UPDATE + dto.getDeviceName());
    }

    /**
     * 删除
     */
    @Log(title = "设备", businessType = BusinessType.DELETE)
    @ApiOperation("删除")
    @GetMapping("/delete/{id}")
    public Result<Void> delete(@PathVariable("id") Long id) {
        deviceRoleService.checkDeviceRole(DeviceControlsTypeEnum.DELETE, id);
        Device device = deviceService.getById(id);
        if (Objects.isNull(device)) {
            return Result.fail("设备不存在");
        }
        deviceService.removeById(id);
        // 删除设备权限
        LambdaQueryWrapper<DeviceRole> lambda = new LambdaQueryWrapper<>();
        lambda.eq(DeviceRole::getDeviceId, id);
        deviceRoleService.remove(lambda);
        // 删除子表
        TableDTO tableDTO = new TableDTO();
        tableDTO.setTableName(TdEngIneConstants.TABLE_PREFIX + id);
        remoteTdEngineService.delTable(tableDTO);
        return Result.ok2Log(LogConstants.DELETE + device.getDeviceName());
    }

    /**
     * 查看
     */
    @ApiOperation("查看")
    @GetMapping("/view/{id}")
    public Result<DeviceDTO> view(@PathVariable Long id) {
        Device device = deviceService.getById(id);
        if (Objects.isNull(device)) {
            return Result.fail("未找到对应数据");
        }
        DeviceDTO dto = deviceConvert.entity2Dto(device);
        List<GroupDTO> groupDTOS = groupDeviceService.listByDeviceId(id);
        if (CollUtil.isNotEmpty(groupDTOS)) {
            dto.setGroupIds(groupDTOS.stream().map(GroupDTO::getId).collect(Collectors.toList()));
        }
        // 备注
        DeviceUserDetails details = deviceUserDetailsService.getOne(new LambdaQueryWrapper<DeviceUserDetails>()
                .eq(DeviceUserDetails::getDeviceId, dto.getId())
                .eq(DeviceUserDetails::getUserId, LoginHelper.getLoginUserId()));
        if (Objects.nonNull(details)){
            dto.setNotes(details.getRemarks());
        }
        return Result.data(dto);
    }

    /**
     * 查看详情
     */
    @ApiOperation("查看详情")
    @GetMapping("/detail/{id}")
    public Result<DeviceDTO> detail(@PathVariable Long id) {
        Device device = deviceService.getById(id);
        if (Objects.isNull(device)) {
            return Result.fail("未找到对应数据");
        }
        DeviceDTO dto = deviceConvert.entity2Dto(device);
        // 场景
        List<GroupDTO> groupDTOS = groupDeviceService.listByDeviceId(id);
        if (CollUtil.isNotEmpty(groupDTOS)) {
            dto.setGroupIds(groupDTOS.stream().map(GroupDTO::getId).collect(Collectors.toList()));
            dto.setGroupNameList(groupDTOS.stream().map(GroupDTO::getName).collect(Collectors.toList()));
        }

        // 变量模版
        Template template = templateService.getById(dto.getTemplateId());
        if (Objects.nonNull(template)) {
            dto.setTemplateName(template.getModelName());
        }
        // 网关
        Gateway gateway = gatewayService.getById(dto.getGatewayId());
        if (Objects.nonNull(gateway)) {
            dto.setGatewayName(gateway.getName());
            dto.setAddress(gateway.getAddress());
            dto.setCardNumber(gateway.getCardNumber());
        }
        dto.setShareNum(0L);
        // 设备所属人
        if (Objects.nonNull(dto.getCreatedBy())) {
            User user = userService.getById(dto.getCreatedBy());
            dto.setAdminName(user.getNickName());

            // 设备分享人数
            LambdaQueryWrapper<DeviceRole> lambda = new LambdaQueryWrapper<>();
            lambda.eq(DeviceRole::getDeviceId, dto.getId());
            lambda.eq(DeviceRole::getStatus, NumberConstant.ZERO_STR);
            lambda.ne(DeviceRole::getRoleType, RoleTypeEnum.ADMIN.getCode());
            dto.setShareNum(deviceRoleService.count(lambda));
        }
        // 备注
        DeviceUserDetails details = deviceUserDetailsService.getOne(new LambdaQueryWrapper<DeviceUserDetails>()
                .eq(DeviceUserDetails::getDeviceId, dto.getId())
                .eq(DeviceUserDetails::getUserId, LoginHelper.getLoginUserId()));
        if (Objects.nonNull(details)){
            dto.setNotes(details.getRemarks());
        }
        return Result.data(dto);
    }

    /**
     * 全量查询
     */
    @ApiOperation("全量查询")
    @GetMapping("/list")
    public Result<List<DeviceDTO>> list() {
        List<DeviceDTO> dtoList = deviceService.selectRole2Device();
        if (CollUtil.isEmpty(dtoList)) {
            return Result.data(CollUtil.newArrayList());
        }
        List<Long> ids = dtoList.stream().map(DeviceDTO::getId).collect(Collectors.toList());
        List<Device> list = deviceService.listByIds(ids);
        if (CollUtil.isNotEmpty(list)) {
            dtoList = list.stream().map(it -> {
                DeviceDTO dto = deviceConvert.entity2Dto(it);
                Template template = templateService.getById(it.getTemplateId());
                if (Objects.nonNull(template)) {
                    dto.setTemplateName(template.getModelName());
                }
                return dto;
            }).collect(Collectors.toList());
        }
        return Result.data(dtoList);
    }

    @Log(title = "设备", businessType = BusinessType.CONTROL)
    @ApiOperation("控制设备")
    @PostMapping("/control")
    public Result<Boolean> control(@RequestBody @Validated ControlDTO dto) {
        deviceRoleService.checkDeviceRole(DeviceControlsTypeEnum.CONTROL, dto.getDeviceId());
        Device device = deviceService.getById(dto.getDeviceId());
        Assert.notNull(device, "设备不存在");
        Variable variable = variableService.getById(dto.getVariableId());
        Assert.notNull(variable, "变量不存在");
        return Result.data2Log(deviceService.control(dto),
                LogConstants.CONTROL + device.getDeviceName() + "-" + variable.getName() + "：" + dto.getParam());
    }

    /**
     * 分页查询
     */
    @ApiOperation("分页查询")
    @PostMapping("/page")
    public PageResult<DeviceDTO> page(@RequestBody BasePageQuery<DeviceDTO> pageParam) {
        List<DeviceDTO> dtoList = deviceService.selectRole2Device();
        if (CollUtil.isEmpty(dtoList)) {
            return PageResult.success(CollUtil.newArrayList(), 0);
        }
        List<Long> ids = dtoList.stream().map(DeviceDTO::getId).collect(Collectors.toList());
        pageParam.getParam().setDeviceIdList(ids);
        IPage<DeviceDTO> page = deviceService.queryPage(pageParam);
        return PageResult.success(page.getRecords(), page.getTotal());
    }

    /**
     * 根据网关编号-从机查询
     */
    @ApiOperation("根据网关id-设备编号查询")
    @PostMapping("/selectByGateWayIdAndDeviceNum")
    public Result<List<DeviceDTO>> selectByGateWayNumAndDeviceNum(@RequestParam Long gateWayId, @RequestParam String address) {
        List<Device> deviceList = deviceService.list(new LambdaQueryWrapper<Device>().eq(Device::getGatewayId, gateWayId).eq(Device::getSlaveAddress, address));
        if (CollUtil.isEmpty(deviceList)) {
            return Result.fail();
        }
        List<DeviceDTO> dtoList = deviceList.stream().map(deviceConvert::entity2Dto).collect(Collectors.toList());
        return Result.data(dtoList);
    }

    /**
     * 根据网关编号-设备编号查询
     */
    @ApiOperation("根据设备id查询")
    @PostMapping("/selectById")
    public Result<DeviceDTO> selectById(@RequestParam Long deviceId) {
        Device device = deviceService.getById(deviceId);
        if (Objects.isNull(device)) {
            return Result.fail();
        }
        return Result.data(deviceConvert.entity2Dto(device));
    }

    /**
     * 查询未关联场景的设备
     */
    @ApiOperation("查询未关联场景的设备")
    @PostMapping("/selectNoGroup2Device")
    public Result<List<DeviceDTO>> selectNoGroup2Device() {
        return Result.data(deviceService.selectNoGroup2Device());
    }

    @GetMapping("/getByGroup")
    @ApiOperation("设备-根据场景查询")
    public Result<List<GroupDTO>> getByGroup() {
        Long loginUserId = LoginHelper.getLoginUserId();
        List<GroupDTO> list = CollUtil.newArrayList();
        LambdaQueryWrapper<Group> lambda = new LambdaQueryWrapper<>();
        lambda.eq(Group::getCreatedBy, LoginHelper.getLoginUserId());
        List<Group> groups = groupService.list(lambda);
        if (CollUtil.isEmpty(groups)) {
            return Result.data(list);
        }

        groups.forEach(it -> {
            GroupDTO groupDTO = groupConvert.entity2Dto(it);
            List<DeviceDTO> dtoList = groupDeviceService.listByGroupId(it.getId(), loginUserId);
            groupDTO.setDeviceDTOList(dtoList);
            list.add(groupDTO);
        });
        return Result.data(list);
    }

    @GetMapping("/getByGroupId/{groupId}")
    @ApiOperation("根据场景Id查询")
    public Result<List<DeviceDTO>> getByGroupId(@PathVariable Long groupId) {
        return Result.data(groupDeviceService.listByGroupId(groupId, LoginHelper.getLoginUserId()));
    }

    @PostMapping("/getAppByGroupId")
    @ApiOperation("小程序根据场景Id查询设备列表")
    public Result<List<DeviceDTO>> getAppByGroupId(@RequestBody DeviceDTO param) {
        if (0L == param.getGroupId()) {
            return Result.data(deviceService.selectNoGroup2DeviceByParam(param));
        }
        return Result.data(groupDeviceService.listByGroupIdByParam(param));
    }

    @ApiOperation("同一个网关下验证设备名是否重复 true-重复")
    @PostMapping("/vfDeviceName")
    public Result<Boolean> vfDeviceName(@RequestBody DeviceDTO param) {
        Long gatewayId = param.getGatewayId();
        String deviceName = param.getDeviceName();
        Long id = param.getId();
        LambdaQueryWrapper<Device> lambda = new LambdaQueryWrapper<>();
        lambda.eq(Device::getGatewayId, gatewayId);
        lambda.eq(Device::getDeviceName, deviceName);
        lambda.ne(Objects.nonNull(id), Device::getId, id);
        long count = deviceService.count(lambda);
        if (count > 0){
            return Result.data(Boolean.TRUE);
        }
        return Result.data(Boolean.FALSE);
    }

    @ApiOperation("导出")
    @GetMapping("/export")
    public void export(HttpServletResponse response, DeviceDTO param) {
        if (Objects.isNull(param) || StrUtil.isEmpty(param.getToken())) {
            return;
        }
        LoginUser loginUser = LoginHelper.getLoginUser(param.getToken());
        if (Objects.isNull(loginUser)) {
            throw new ServiceException("未登录");
        }
        List<DeviceDTO> dtoList = deviceService.selectRole2Token(param.getToken());
        if (CollUtil.isEmpty(dtoList)) {
            throw new ServiceException("暂无数据");
        }
        List<Long> ids = dtoList.stream().map(DeviceDTO::getId).collect(Collectors.toList());
        param.setDeviceIdList(ids);
        List<DeviceDTO> list = deviceService.selectDeviceList(param);
        if (CollUtil.isEmpty(list)) {
            list = CollUtil.newArrayList();
        }
        AtomicInteger index = new AtomicInteger(1);
        list.forEach(it -> {
            Gateway gateway = gatewayService.getById(it.getGatewayId());
            if (Objects.nonNull(gateway)) {
                it.setGatewayName(gateway.getName());
                it.setAddress(gateway.getAddress());
            }

            Template template = templateService.getById(it.getTemplateId());
            if (Objects.nonNull(template)) {
                it.setTemplateName(template.getModelName());
            }

            List<GroupDTO> groupDTOS = groupDeviceService.listByDeviceIdAndUserId(it.getId(), loginUser.getUserId());
            if (CollUtil.isNotEmpty(groupDTOS)) {
                List<String> collect = groupDTOS.stream().map(GroupDTO::getName).collect(Collectors.toList());
                it.setGroupNameStr(String.join(",", collect));
            }

            it.setStatusStr("离线");
            if (Objects.nonNull(it.getStatus()) && it.getStatus()) {
                it.setStatusStr("在线");
            }
            it.setIndex(index.getAndIncrement());
        });
        ExcelUtil.exportExcel(list, "数据", "设备", DeviceDTO.class, response);
    }
}
